Function decoration

텐서플로 v2는 텐서플로 v1에 비해 프로그래밍 스타일이 단순해지고, 명시적인 그래프와 세션 생성 단계를 생략할 수 있다.

하지만 텐서플로 v2의 동적 계산 그래프 모드로 계산하면, 정적 계산 그래프 만큼 효율적이지는 않다.
따라서 텐서플로 v2는 빠른 실행을 위해 파이썬 코드를 텐서플로 그래프 코드로 자동 변환해 주는 AutoGraph 도구를 제공한다.
또한 보통의 파이썬 함수를 텐서플로의 정적 그래프로 컴파일 하는 방법을 제공한다.
@tf.function(데코레이터)
@tf.function
def compute_z(a, b, c):
r1=tf.subtract(a, b)
r2=tf.multiply(2, r1)
z=tf.add(r2, c)
return z
데코레이터(@)를 사용하면 이전과 동일한 방식으로 호출하고 사용할 수 있지만, 입력 매개변수에 기반하여 정적 그래프를 만든다.

파이썬은 동적 타이핑(dynamic typing)과 다형성(polymorphism)을 지원한다.
ex)
def(a, b): return a+b를 정의하면, 입력으로 정수, 실수, 리스트, 문자열을 입력으로 사용하여 호출 가능

원래 텐서플로 그래프는 정적 타입과 크기가 필요하지만, tf.function은 동적 타이핑을 처리할 수 있다.
tf.print(' :', compute_z(1, 2, 3))
tf.print(' 1 :', compute_z([1], [2], [3]))
tf.print(' 2 :', compute_z([[1]], [[2]], [[3]]))
@tf.function을 사용하지 않았을 때와 동일한 출력값을 출력하지만,
이번에는 텐서플로가 입력 매개변수를 기반으로 그래프를 구성하기 위해 트레이싱(tracing) 기법을 사용한다.

트레이싱 기법을 사용해서 텐서플로는 함수호출에 사용된 입력 시그니처(signature)를 기반으로 키(cache key)의 튜플을 생성한다.
키(cache key)
- tf.Tensor 매개변수이면 키는 크기와 데이터 기반으로 한다.
- 리스트와 같은 파이썬 타입이면, id() 함수를 이용하여 키를 생성한다.(tf.variable도 id를 통해서 키를 생성)
- 파이썬 원시 자료형(primitive value)이면 키는 입력 값을 기반으로 한다.
데코레이터가 호출되면 텐서플로는 해당 키에 맞는 그래프가 이미 생성되었는지 체크한다.
그래프가 없다면 텐서플로는 새로 그래프를 생성하고 해당 키를 저장한다.

함수를 호출할 수 있는 경우를 제한하려면, tf.TensorSpec 객체의 튜플로 입력 시그니처를 지정할 수 있다.
tf.in32 타입의 랭크 1 텐서만 받을 수 있는 compute_z
@tf.function(input_signature=(tf.TensorSpec(shape=[None], dtype=tf.int32), tf.TensorSpec(shape=[None], dtype=tf.int32), tf.TensorSpec(shape=[None], dtype=tf.int32),))
def compute_z(a, b, c):
r1=tf.subtract(a, b)
r2=tf.multiply(2, r1)
z=tf.add(r2, c)
return z
랭크 1 텐서(또는 랭크 1 텐서로 바꿀 수 있는 리스트) 입력
tf.print('Rank 1 Inputs:', compute_z([1], [2], [3]))
tf.print('Rank 1 Inputs:', compute_z([1, 2], [2, 4], [3, 6]))

Rank 1 Inputs: [1]

Rank 1 Inputs: [1 2]

tf.print('Rank 0 Inputs:', compute_z(1, 2, 3)

ValueError: Python inputs incompatible with input_signature:

  inputs: (

    1,

    2,

    3)

  input_signature: (

    TensorSpec(shape=(None,), dtype=tf.int32, name=None),

    TensorSpec(shape=(None,), dtype=tf.int32, name=None),

    TensorSpec(shape=(None,), dtype=tf.int32, name=None))